package com.starlink.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.hutool.core.convert.Convert;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageHelper;
import com.starlink.common.annotation.client.WeixinJsClient;
import com.starlink.common.annotation.client.weixin.UserPurchaseRes;
import com.starlink.common.annotation.client.weixin.WeixinJsCreateOrderReq;
import com.starlink.common.annotation.client.weixin.WeixinJsCreateOrderRes;
import com.starlink.common.config.WechatConfigurationConfig;
import com.starlink.context.SessionContext;
import com.starlink.model.request.mall.WechatPay;
import com.starlink.utils.OrderNumUtil;
import com.starlink.utils.WeixinUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.springframework.data.domain.Pageable;
import com.starlink.common.utils.AssertUtil;
import com.starlink.model.dtomapper.UserVipPaymentDtoMapper;
import com.starlink.model.domain.UserVipPaymentDO;
import com.starlink.mapper.UserVipPaymentMapper;
import com.starlink.model.request.UserVipPaymentRequest;
import com.starlink.service.UserVipPaymentService;
import com.starlink.model.util.UserVipPaymentConvert;
import com.starlink.model.vo.UserVipPaymentVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.starlink.common.enums.OrderTypeEnum.DEPOSIT;
import static com.starlink.common.enums.OrderTypeEnum.OPEN_VIP;
import static com.starlink.utils.PageUtils.getOrderBy;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.util.List;
import java.util.UUID;

/**
 * @author zhanghong
 */
@Service
public class UserVipPaymentServiceImpl extends ServiceImpl<UserVipPaymentMapper, UserVipPaymentDO> implements UserVipPaymentService {
    @Autowired
    private UserVipPaymentMapper userVipPaymentMapper;
    @Autowired
    private WeixinJsClient weixinJsClient;

    @Override
    public UserVipPaymentVO getByKey(long id) {
        UserVipPaymentVO userVipPaymentVO = UserVipPaymentDtoMapper.INSTANCE.do2VO(getById(id));
        return userVipPaymentVO;
    }

    @Override
    public PageInfo<UserVipPaymentVO> pageQuery(Pageable pageable,UserVipPaymentRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<UserVipPaymentDO> list = userVipPaymentMapper.pageQuery(request, request.getPageSize(), request.fetchOffSet());
        List<UserVipPaymentVO> userVipPaymentVOList = UserVipPaymentConvert.buildUserVipPaymentVoList(list);
        return new PageInfo(userVipPaymentVOList);
    }

    @Override
    public List<UserVipPaymentVO> listQuery(UserVipPaymentRequest request) {
        List<UserVipPaymentDO> list = userVipPaymentMapper.selectDOList(UserVipPaymentDtoMapper.INSTANCE.request2DO(request));
        List<UserVipPaymentVO> userVipPaymentVOS = UserVipPaymentConvert.buildUserVipPaymentVoList(list);
        return userVipPaymentVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(UserVipPaymentRequest request) {
        save(UserVipPaymentDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByKey(UserVipPaymentRequest request) {
        AssertUtil.assertNotNull(request.getId(), "id不能为空");
        saveOrUpdate(UserVipPaymentDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteDOByIds(String ids) {
        userVipPaymentMapper.deleteDOByIds(Convert.toStrArray(ids));
        return true;
    }

    @Override
    public UserPurchaseRes openVip(UserVipPaymentRequest request) {
        String openId = request.getOpenId();
        BigDecimal amount = request.getAmount();
        Long userId = SessionContext.getWechatUserId();
        AssertUtil.assertNotNull(userId,"用户ID获取失败!");
        AssertUtil.assertNotNull(openId,"openId不能为空!");
        AssertUtil.assertNotNull(amount,"金额不能为空!");
        UserPurchaseRes purchaseRes = new UserPurchaseRes();
        String orderNum = "VIP"+OrderNumUtil.createUniqueOrderNum();
        WechatPay wechatPay = new WechatPay();
        wechatPay.setOrderType(OPEN_VIP.getType());
        wechatPay.setAmount(amount.toPlainString());
        wechatPay.setUserId(userId);
        String attach = JSONObject.toJSONString(wechatPay);
        WeixinJsCreateOrderReq req = new WeixinJsCreateOrderReq(orderNum, amount.doubleValue(), attach, openId,"开通VIP");
        try {
            WeixinJsCreateOrderRes res = weixinJsClient.createOrder(req);
            buildPayRes(purchaseRes, res.getPrepay_id());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("VIP开通失败!");
        }
        return purchaseRes;
    }

    /**
     * 组装下单支付参数
     *
     * @param res
     * @param prepayId
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     * @throws SignatureException
     * @throws InvalidKeyException
     */
    private void buildPayRes(UserPurchaseRes res, String prepayId) throws UnsupportedEncodingException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        res.setAppId(WechatConfigurationConfig.wxUserWechatAppid);
        res.setTimeStamp(System.currentTimeMillis() / 1000 + "");
        res.setNonceStr(UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
        res.setSignType("RSA");
        res.setDetailExtend("prepay_id=" + prepayId);
        // 签名，使用字段appId、timeStamp、nonceStr、package计算得出的签名值
        String preSign = res.getAppId() + "\n" + res.getTimeStamp() + "\n" + res.getNonceStr() + "\n" + res.getDetailExtend() + "\n";
        PrivateKey privateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(WechatConfigurationConfig.wxUserWechatPayApiClientKey.getBytes("utf-8")));
        String paySign = WeixinUtil.sign(preSign.getBytes(StandardCharsets.UTF_8), privateKey);
        res.setPaySign(paySign);
    }
}
